#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include "Task.hpp"
#include "Log.hpp"

#define NUM 3

class ThreadPool {
    private:
        int num; // 创建多少个线程
        bool stop;  // 记录是否需要终止
        std::queue<Task> task_queue;  // 任务队列
        pthread_mutex_t lock; 
        pthread_cond_t cond;
        static ThreadPool *single_instance;
        ThreadPool(int _num = NUM)
            :num(_num)
        {
            pthread_mutex_init(&lock, nullptr);
            pthread_cond_init(&cond, nullptr);
        }
        ThreadPool(const ThreadPool &) {};
    public:
        static ThreadPool* getInstance() {
            pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
            if (single_instance == nullptr) {
                pthread_mutex_lock(&_mutex);
                if (single_instance == nullptr) {
                    single_instance = new ThreadPool();
                    single_instance->InitThreadPool();
                }
                pthread_mutex_unlock(&_mutex);
            }
            return single_instance;
        }
        bool IsStop() {
            return stop;
        }
        bool IsEmpty() {
            return task_queue.size() == 0 ? true : false;
        }
        void ThreadWait() {
            pthread_cond_wait(&cond, &lock);
        }
        void ThreadWakeup() {
            pthread_cond_signal(&cond);
        }
        static void *ThreadRoutine(void *args) {
            ThreadPool *tp = (ThreadPool *)args;
            while (true) {
                Task t;
                tp->Lock();
                while (tp->IsEmpty()) {
                    tp->ThreadWait();
                }
                tp->PopTask(t);
                tp->Unlock();
                t.ProcessOn();  // 不要在临界区内进行任务处理
            }
        }

        bool InitThreadPool() {
            for (int i = 0; i < num; ++i) {
                pthread_t tid;
                if (pthread_create(&tid, nullptr, ThreadRoutine, this) != 0) {
                    LOG(ERROR, "create thread pool error!");
                    return false;
                }
            }
            LOG(INFO, "create thread pool success!");
            return true;
        }
        void Lock() {
            pthread_mutex_lock(&lock);
        }
        void Unlock() {
            pthread_mutex_unlock(&lock);
        }
        void PushTask(const Task &task) {
            Lock(); 
            task_queue.push(task);
            Unlock();
            ThreadWakeup();
        }
        void PopTask(Task &task) {
            // 之前例程里已经加过锁了，这里再加的话会阻塞
            // Lock();
            task = task_queue.front();
            task_queue.pop();
            // Unlock();
        }

        ~ThreadPool() {
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&cond);
        }
};

ThreadPool* ThreadPool::single_instance = nullptr;